package com.xrui.hbase.schema;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;

import java.util.ArrayList;
import java.util.List;

public class RowKeyFormat {
    private RowKeyEncoding encoding;
    private String delimiter;
    private int hashSize = 0;
    private List<RowKeyComponent> components;
    private String decoder;
    private String encoder;
    private String hasher;

    public List<RowKeyComponent> getComponents() {
        return components;
    }

    public void setComponents(List<RowKeyComponent> components) {
        this.components = components;
    }

    public String getEncoder() {
        return encoder;
    }

    public void setEncoder(String encoder) {
        this.encoder = encoder;
    }

    public String getDecoder() {
        return decoder;
    }

    public void setDecoder(String decoder) {
        this.decoder = decoder;
    }

    public RowKeyEncoding getEncoding() {
        return encoding;
    }

    public void setEncoding(RowKeyEncoding mEncoding) {
        this.encoding = mEncoding;
    }

    public String getDelimiter() {
        return delimiter;
    }

    public void setDelimiter(String delimiter) {
        this.delimiter = delimiter;
    }

    public int getHashSize() {
        return hashSize;
    }

    public void setHashSize(int mHashSize) {
        this.hashSize = mHashSize;
    }

    public String getHasher() {
        return hasher;
    }

    public void setHasher(String hasher) {
        this.hasher = hasher;
    }

    public boolean isHashed() {
        for (RowKeyComponent rowKeyComponent : components) {
            if (rowKeyComponent.isHashed()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(RowKeyFormat.class)
            .add("type", encoding)
            .add("encoder", encoder)
            .add("decoder", decoder)
            .add("hasher", hasher)
            .add("hash size", hashSize)
            .add("delimiter", delimiter)
            .add("components", components)
            .toString();
    }

    public static class RowKeyFormatBuilder {
        private List<RowKeyComponent> mComponents = new ArrayList<>();
        private String mDelimiter;
        private RowKeyEncoding mEncoding;
        private int mHashSize;
        private String mEncoder;
        private String mDecoder;
        private String mHasher;

        public static RowKeyFormatBuilder newBuilder() {
            return new RowKeyFormatBuilder();
        }

        public RowKeyFormatBuilder withEncoder(String encoder) {
            mEncoder = encoder;
            return this;
        }

        public RowKeyFormatBuilder withDecoder(String decoder) {
            mDecoder = decoder;
            return this;
        }

        public RowKeyFormatBuilder withEncoding(RowKeyEncoding encoding) {
            mEncoding = encoding;
            return this;
        }

        public RowKeyFormatBuilder withHasher(String hasher) {
            mHasher = hasher;
            return this;
        }

        public RowKeyFormatBuilder addComponent(RowKeyComponent rowKeyComponent) {
            if (rowKeyComponent.isHashed() && mComponents.size() > 0) {
                RowKeyComponent lastComponent = mComponents.get(mComponents.size() - 1);
                Preconditions.checkArgument(
                    null == lastComponent || lastComponent.isHashed() || !rowKeyComponent.isHashed(),
                    "Hashed components should not before a un-hashed component: " + rowKeyComponent.getName()
                );
            }
            mComponents.add(rowKeyComponent);
            return this;
        }

        public RowKeyFormatBuilder withComponents(List<RowKeyComponent> rowKeyComponents) {
            Preconditions.checkNotNull(rowKeyComponents);
            boolean hashEnded = false;
            for (RowKeyComponent rowKeyComponent : rowKeyComponents) {
                if (!rowKeyComponent.isHashed()) {
                    hashEnded = true;
                } else {
                    Preconditions.checkArgument(
                        !hashEnded || !rowKeyComponent.isHashed(),
                        "Hashed components should not before a un-hashed component: " + rowKeyComponent.getName()
                    );
                }
            }
            mComponents = rowKeyComponents;
            return this;
        }

        public RowKeyFormatBuilder withDelimiter(String delimiter) {
            mDelimiter = delimiter;
            return this;
        }

        public RowKeyFormatBuilder withHashSize(int size) {
            mHashSize = size;
            return this;
        }

        public RowKeyFormat build() {
            Preconditions.checkNotNull(mDecoder);
            RowKeyFormat rowKeyFormat = new RowKeyFormat();
            rowKeyFormat.setDecoder(mDecoder);
            rowKeyFormat.setEncoder(mEncoder);
            rowKeyFormat.setComponents(mComponents);
            rowKeyFormat.setDelimiter(mDelimiter);
            rowKeyFormat.setHasher(mHasher);
            rowKeyFormat.setHashSize(mHashSize);
            rowKeyFormat.setEncoding(mEncoding);
            return rowKeyFormat;
        }
    }
}
